#include "StdAfx.h"
#include "Listener.hpp"

using namespace HpsFramework::Network;

void HpsFramework::Network::Listener::stopListening()
{
	if(this->_listenSocket.isValid () || this->alive())
	{
		this->stop (true); // TODO: can be set to false?
	}
}

bool HpsFramework::Network::Listener::startListening( Address& addr )
{
	if ( this->_listenSocket.isValid() ) 
	{
		HPS_THROW(SocketAlreadyCreated, 0);
		return false;
	}
	if ( !this->_listenSocket.create (WSA_FLAG_OVERLAPPED) )
	{
		HPS_THROW(SocketCreationFailed, WSAGetLastError());
		return false;
	}
	if ( this->_listenSocket.listen(addr) ) 
	{
		this->_listenEvent.select ( this->_listenSocket.getSocket (), FD_ACCEPT );
		return this->start();
	} 
	else 
	{
		return false;
	}
}

HpsFramework::Network::Listener::~Listener()
{
	this->stopListening();
}

HpsFramework::Network::Listener::Listener()
{

}

int HpsFramework::Network::Listener::run()
{

	WSANETWORKEVENTS events;

	while(!this->waitForExit(1))
	{

		if ( this->_listenEvent.wait(100) )
		{

			int ret = WSAEnumNetworkEvents (
				this->_listenSocket.getSocket(), 
				this->_listenEvent.getEvent(), &events 
				);

			if(ret == SOCKET_ERROR)
				return 1;

			if(events.lNetworkEvents & FD_ACCEPT)
			{
				if(events.iErrorCode[FD_ACCEPT_BIT] == 0)
				{
					this->handleAccept();
				}
				else
				{
					return 1;
				}
			}

		}
	}
	this->_listenSocket.close();
	
	return 0;

}

void HpsFramework::Network::Listener::handleAccept()
{
	int addrlen = sizeof(sockaddr);
	Network::Address::AddressType address;
	Network::Socket::SocketType remoteSocket = WSAAccept ( this->_listenSocket.getSocket(), (sockaddr*)&address, &addrlen, NULL, 0 );
	if(remoteSocket == SOCKET_ERROR)
	{
		if(remoteSocket != WSAEWOULDBLOCK)
		{
			return;
		}
	}

	Network::Address remoteAddress ( address );

	if(!this->handleConnection( Socket(remoteSocket), remoteAddress ))
	{
		closesocket (remoteSocket);
		return;
	}
}

void HpsFramework::Network::Listener::setServer( Network::Server* srv )
{
	this->_server = srv;
}

HpsFramework::Network::Server* HpsFramework::Network::Listener::getServer()
{
	return this->_server;
}
